package validator

import (
	"encoding/json"
	"fmt"
	"net"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unicode/utf8"
)

/** ------ 获取标签的值 ------ */
// 获取tag [`valid:"in:1,2,3;required"`] -->in:1,2,3  required
func TagTypes(str string) []string {
	return strings.Split(str, ";")
}

// 获取tag [`valid:"in:1,2,3"`] -->["in","1,2,3"]
func TagTypeItems(str string) []string {
	return strings.Split(str, ":")
}

// 获取tag [`valid:"in:1,2,3"`] -->[1,2,3]
func TagValItem(str string) []string {
	return strings.Split(str, ",")
}

// 获取tag对应的type的值
func TypeValue(tagTypes []string, typeName string) string {
	for _,v := range tagTypes{ // v---> comment:用户名
		item := TagTypeItems(v) // item---> [comment, 用户名]
		if len(item) == 2 && item[0] == typeName && item[1] != ""{
			return item[1]
		}
	}
	return ""
}

/** ----- 参数验证 -----*/

// 判断valid标签中是否含有 optional
func HasOptional(str string) bool {
	return HasSpecialType(str, OptionType)
}

// 是否有comment
func HasComment(str string) bool {
	return HasSpecialType(str, CommentType)
}

// 是否有confirm
func HasConfirm(str string) bool {
	return HasSpecialType(str, ConfirmType)
}

// 是否含有指定type
func HasSpecialType(str, special string) bool  {
	tagTypes := TagTypes(str)
	for _, v := range tagTypes {
		item := TagTypeItems(v)
		if len(item) == 2 && item[0] == special && item[1] != "" {
			return true
		}
	}
	return false
}

// 判断是否为已定义的type类型
func IsDefineType(tagType string) bool  {
    for k1 := range TagTypeMap {
        if k1 == tagType {
            return true
        }
    }
    for k2 := range ParamTypeMap {
        if k2 == tagType {
            return true
        }
    }
    return false
}

// 判断是否在TagTypeMap中
func IsInTagType(tagType string) bool {
    for k := range TagTypeMap {
        if k == tagType {
            return true
        }
    }
    return false
}

// 判断是否在ParamTypeMap中
func IsInParamsTagType(tagType string) bool  {
    for k2 := range ParamTypeMap {
        if k2 == tagType {
            return true
        }
    }
    return false
}

// 非空验证
func IsEmptyValue(value reflect.Value) bool {
	switch value.Kind() {
	case reflect.String:
		return value.Len() == 0
	case reflect.Map, reflect.Array:
		return value.Len() == 0 || value.IsNil()
	case reflect.Bool:
		return !value.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return value.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return value.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return value.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return value.IsNil()
	}
	return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}

// 字符串是否为空
func IsNull(str string) bool {
	return len(str) == 0
}

// 不为空
func IsNotNull(str string) bool {
	return !IsNull(str)
}

// 是否是整型
func IsInt(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexInt.MatchString(str)
}

// 是否是float
func IsFloat(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexFloat.MatchString(str)
}

// 是否是字母
func IsAlpha(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexAlpha.MatchString(str)
}

// 检测是否包含字母数字
func IsAlphaNum(str string) bool {
	if IsNull(str) {
		return true
	}
	return rexAlphaNum.MatchString(str)
}

// 检测字母 数字 破折号 下划线
func IsAlphaDash(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexAlphaDash.MatchString(str)
}

// 检测字母 数字 汉字
func IsAlphaNormal(str string) bool  {
	if IsNull(str) {
		return false
	}
	return rexAlphaNormal.MatchString(str)
}

// 是否是数字
func IsNumeric(str string) bool {
	if IsNull(str) {
		return true
	}
	return rexNumeric.MatchString(str)
}

// 邮箱验证
func IsEmail(str string) bool {
	// TODO uppercase letters are not supported
	return rexEmail.MatchString(str)
}

func IsBase64(str string) bool {
	return rexBase64.MatchString(str)
}

// ipv4检测
func IsIPv4(str string) bool {
	ip := net.ParseIP(str)
	return ip != nil && strings.Contains(str, ".")
}

// ipv6检测
func IsIPv6(str string) bool {
	ip := net.ParseIP(str)
	return ip != nil && strings.Contains(str, ":")
}

// 检测手机格式是否正确
func IsMobile(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexMobile.MatchString(str)
}

// 密码格式检测
func IsPasswordFormat(str string) bool {
	if IsNull(str) {
		return false
	}
	alpha := `[[:alpha:]]{1}`
	digit := `[[:digit:]]{1}`
	full := "^[[:alnum:]!#\\$%&\\^\\-\\+\\._@\\?\\/'|]{6,20}$"
	// 检测是否包含字母
	if !regexp.MustCompile(alpha).MatchString(str) {
		return false
	}
	// 检测是否包含数字
	if !regexp.MustCompile(digit).MatchString(str) {
		return false
	}
	// 全验证
	if regexp.MustCompile(full).MatchString(str){
		return true
	}
	return false
}

// 两个值的比较
func IsConfirm(str string, params ...string) bool {
	return str == params[0]
}

// 身份证号检测
func IsIdCard(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexIdCard.MatchString(str)
}

// 判断值是否介于指定的范围内
func ValueBetween(str string, params ...string) bool {
    if len(params) == 2 {
        value, _ := ToFloat(str)
        min, _ := ToFloat(params[0])
        max, _ := ToFloat(params[1])
        return InRange(value, min, max)
    }
	return false
}

// 判断string长度是否介于指定的范围内
func LengthBetween(str string, params ...string) bool  {
	if len(params) == 2 {
		strLength := utf8.RuneCountInString(str)
		min, _ := ToInt(params[0])
		max, _ := ToInt(params[1])
		return strLength >= int(min) && strLength <= int(max)
	}

	return false
}

// 检测值是否在指定的数组中
func IsIn(str string, params ...string) bool  {
    for _, param := range params{
        if str == param {
            return true
        }
    }
    return false
}

func InRange(value interface{}, left interface{}, right interface{}) bool {
    switch value.(type) {
    case int:
        intValue, _ := ToInt(value)
        intLeft, _ := ToInt(left)
        intRight, _ := ToInt(right)
        return InRangeInt(intValue, intLeft, intRight)
    case float32, float64:
        intValue, _ := ToFloat(value)
        intLeft, _ := ToFloat(left)
        intRight, _ := ToFloat(right)
        return InRangeFloat64(intValue, intLeft, intRight)
    case string:
        return value.(string) >= left.(string) && value.(string) <= right.(string)
    default:
        return false
    }
}

func InRangeInt(value, left, right interface{}) bool {
    value64, _ := ToInt(value)
    left64, _ := ToInt(left)
    right64, _ := ToInt(right)
    if left64 > right64 {
        left64, right64 = right64, left64
    }
    return value64 >= left64 && value64 <= right64
}

func InRangeFloat64(value, left, right float64) bool {
    if left > right {
        left, right = right, left
    }
    return value >= left && value <= right
}

// 是否大于或等于最少数
func IsMin(str string, params ...string) bool {
	if len(params) == 1 {
		value,_ := ToFloat(str)
		min,_ := ToFloat(params[0])
		return value >= min
	}
	return false
}

// 是否小于或等于最大数
func IsMax(str string, params ...string) bool {
	if len(params) == 1 {
		value,_ := ToFloat(str)
		max,_ := ToFloat(params[0])
		return value <= max
	}
	return false
}

// 长度是否等于size的值
func IsSize(str string, params ...string) bool {
	return false
}

// 检测是否是汉字
func IsChinese(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexChinese.MatchString(str)
}

// 判断是否是uuid
func IsUUID(str string) bool {
	if IsNull(str) {
		return false
	}
	return rexUuid.MatchString(str)
}

/** ------ type converter ---- */

// 转换成int类型
func ToInt(value interface{}) (res int64, err error) {
	val := reflect.ValueOf(value)

	switch value.(type) {
	case int, int8, int16, int32, int64:
		res = val.Int()
	case uint, uint8, uint16, uint32, uint64:
		res = int64(val.Uint())
	case float32, float64:
		res = int64(val.Float())
	case string:
		if IsInt(val.String()) {
			res, err = strconv.ParseInt(val.String(), 0, 64)
			if err != nil {
				res = 0
			}
		} else {
			err = fmt.Errorf("ToInt: invalid numeric format %g", value)
			res = 0
		}
	default:
		err = fmt.Errorf("ToInt: unknown interface type %T", value)
		res = 0
	}

	return
}

// 转换成float类型
func ToFloat(value interface{}) (res float64, err error) {
	val := reflect.ValueOf(value)

	switch value.(type) {
	case int, int8, int16, int32, int64:
		res = float64(val.Int())
	case uint, uint8, uint16, uint32, uint64:
		res = float64(val.Uint())
	case float32, float64:
		res = val.Float()
	case string:
		res, err = strconv.ParseFloat(val.String(), 64)
		if err != nil {
			res = 0
		}
	default:
		err = fmt.Errorf("ToInt: unknown interface type %T", value)
		res = 0
	}

	return
}

// 转换成json类型
func ToJSON(obj interface{}) (string, error) {
	res, err := json.Marshal(obj)
	if err != nil {
		res = []byte("")
	}
	return string(res), err
}

// 转换成string类型
func ToString(obj interface{}) string {
	res := fmt.Sprintf("%v", obj)
	return res
}

// 转换成boolean类型
func ToBoolean(str string) (bool, error) {
	return strconv.ParseBool(str)
}
